//
// Created by ZengYun on 2024/6/4.
//

#include "WeatherSensor.h"
#include "Tools.h"

using namespace app::Clusters;
using namespace app::Clusters::TemperatureMeasurement::Attributes;
using namespace app::Clusters::RelativeHumidityMeasurement::Attributes;

namespace {

DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(temperatureSensorAttrs)
                DECLARE_DYNAMIC_ATTRIBUTE(TemperatureMeasurement::Attributes::MeasuredValue::Id, INT16S, 2, 0),
                DECLARE_DYNAMIC_ATTRIBUTE(TemperatureMeasurement::Attributes::MinMeasuredValue::Id, INT16S, 2, 0),
                DECLARE_DYNAMIC_ATTRIBUTE(TemperatureMeasurement::Attributes::MaxMeasuredValue::Id, INT16S, 2, 0),
        DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();

EmberAfCluster temperatureSensorClusters = DECLARE_DYNAMIC_CLUSTER(TemperatureMeasurement::Id, temperatureSensorAttrs,
                                                                   ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr);

// MeasuredValue = 100 x water content
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(humiditySensorAttributes)
                DECLARE_DYNAMIC_ATTRIBUTE(RelativeHumidityMeasurement::Attributes::MeasuredValue::Id, INT16U, 2, 0),
                DECLARE_DYNAMIC_ATTRIBUTE(RelativeHumidityMeasurement::Attributes::MinMeasuredValue::Id, INT16U, 2, 0),
                DECLARE_DYNAMIC_ATTRIBUTE(RelativeHumidityMeasurement::Attributes::MaxMeasuredValue::Id, INT16U, 2, 0),
        DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();

EmberAfCluster humidifySensorClusters = DECLARE_DYNAMIC_CLUSTER(RelativeHumidityMeasurement::Id, humiditySensorAttributes,
                                                                   ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr);

}


TemperatureSensor::TemperatureSensor(const ::BasicInformation *node)
        : BridgedDevice(node) {
    ChipLogProgress(DeviceLayer, "Temperature Sensor");
    mClusters.push_back(temperatureSensorClusters);
    mMeasurement = 2500;
}

Protocols::InteractionModel::Status TemperatureSensor::ReadAttribute(
        ClusterId clusterId,
        AttributeId attributeId,
        uint8_t *buffer,
        uint16_t maxReadLength) {
    if (clusterId != TemperatureMeasurement::Id) {
        return BridgedDevice::ReadAttribute(clusterId, attributeId, buffer, maxReadLength);
    }
    ChipLogProgress(DeviceLayer, "ReadAttribute: attrId=%d, maxReadLength=%d", attributeId, maxReadLength);

    if (attributeId == TemperatureMeasurement::Attributes::MeasuredValue::Id) {
        tools::GetAttr(buffer, maxReadLength, GetMeasuredValue());
    } else if (attributeId == TemperatureMeasurement::Attributes::MaxMeasuredValue::Id) {
        tools::GetAttr(buffer, maxReadLength, int16_t(10000));
    } else if (attributeId == TemperatureMeasurement::Attributes::MinMeasuredValue::Id) {
        tools::GetAttr(buffer, maxReadLength, int16_t(-3200));
    } else {
        return Protocols::InteractionModel::Status::UnsupportedRead;
    }

    return Protocols::InteractionModel::Status::Success;
}

void TemperatureSensor::SetMeasuredValue(int16_t measurement) {
    const bool changed = mMeasurement != measurement;
    mMeasurement = measurement;
    ChipLogProgress(DeviceLayer, "Device[%s] new measurement=\"%d\"",
                    GetName().c_str(), measurement);

    if (changed) {
        NotifyStatusChanged(TemperatureMeasurement::Id, TemperatureMeasurement::Attributes::MeasuredValue::Id);
    }
}

ChipError TemperatureSensor::OnReport(const DataBlock *block) {
    if (block->path.clusterId != TemperatureMeasurement::Id) {
        return BridgedDevice::OnReport(block);
    }

    if (block->path.attributeId == TemperatureMeasurement::Attributes::MeasuredValue::Id) {
        SetMeasuredValue(static_cast<int16_t>(block->data.asInt()));
    }
    return CHIP_NO_ERROR;
}

ChipError TemperatureSensor::OnReadAttributes() {
    GetRemoteAttribute(TemperatureMeasurement::Id, TemperatureMeasurement::Attributes::MeasuredValue::Id);
    return CHIP_NO_ERROR;
}

int16_t TemperatureSensor::GetMeasuredValue() const {
    return mMeasurement;
}

HumiditySensor::HumiditySensor(const ::BasicInformation *node)
    : BridgedDevice(node) {
    ChipLogProgress(DeviceLayer, "Humidity Sensor");
    mClusters.push_back(humidifySensorClusters);
    mMeasurement = 7000;
}

int16_t HumiditySensor::GetMeasuredValue() const {
    return mMeasurement;
}

void HumiditySensor::SetMeasuredValue(int16_t measurement) {
    const bool changed = mMeasurement != measurement;
    mMeasurement = measurement;
    ChipLogProgress(DeviceLayer, "Device[%s] new measurement=\"%d\"",
                    GetName().c_str(), measurement);

    if (changed) {
        NotifyStatusChanged(RelativeHumidityMeasurement::Id, RelativeHumidityMeasurement::Attributes::MeasuredValue::Id);
    }
}

Protocols::InteractionModel::Status
HumiditySensor::ReadAttribute(ClusterId clusterId, AttributeId attributeId, uint8_t *buffer, uint16_t maxReadLength) {
    if (clusterId != RelativeHumidityMeasurement::Id) {
        return BridgedDevice::ReadAttribute(clusterId, attributeId, buffer, maxReadLength);
    }
    ChipLogProgress(DeviceLayer, "ReadAttribute: attrId=%d, maxReadLength=%d", attributeId, maxReadLength);

    if (attributeId == RelativeHumidityMeasurement::Attributes::MeasuredValue::Id) {
        tools::GetAttr(buffer, maxReadLength, GetMeasuredValue());
    } else if (attributeId == RelativeHumidityMeasurement::Attributes::MaxMeasuredValue::Id) {
        tools::GetAttr(buffer, maxReadLength, int16_t(10000));
    } else if (attributeId == RelativeHumidityMeasurement::Attributes::MinMeasuredValue::Id) {
        tools::GetAttr(buffer, maxReadLength, int16_t(0));
    } else {
        return Protocols::InteractionModel::Status::UnsupportedRead;
    }

    return Protocols::InteractionModel::Status::Success;
}

ChipError HumiditySensor::OnReadAttributes() {
    GetRemoteAttribute(RelativeHumidityMeasurement::Id, RelativeHumidityMeasurement::Attributes::MeasuredValue::Id);
    return CHIP_NO_ERROR;
}

ChipError HumiditySensor::OnReport(const DataBlock *block) {
    if (block->path.clusterId != RelativeHumidityMeasurement::Id) {
        return BridgedDevice::OnReport(block);
    }

    if (block->path.attributeId == RelativeHumidityMeasurement::Attributes::MeasuredValue::Id) {
        SetMeasuredValue(static_cast<int16_t>(block->data.asInt() * 100));
    }
    return CHIP_NO_ERROR;
}
